"""
瞄准线模块
实现十字瞄准线的显示、校准和样式管理
"""

import cv2
import numpy as np
from typing import Tuple, Dict, Optional
import json
import logging

class Crosshair:
    """瞄准线管理器"""
    
    def __init__(self, frame_width: int = 640, frame_height: int = 480):
        """
        初始化瞄准线
        
        Args:
            frame_width: 画面宽度
            frame_height: 画面高度
        """
        self.frame_width = frame_width
        self.frame_height = frame_height
        
        # 瞄准线位置（相对于画面中心的偏移）
        self.offset_x = 0
        self.offset_y = 0
        
        # 瞄准线样式配置
        self.style = "cross"  # cross, dot, circle
        self.color = (0, 255, 0)  # 绿色
        self.thickness = 2
        self.size = 20
        self.opacity = 1.0
        
        # 校准模式
        self.calibration_mode = False
        self.calibration_points = []  # 校准点列表
        
        # 设置日志
        self.logger = logging.getLogger(__name__)
        
    def set_position(self, x: int, y: int):
        """
        设置瞄准线位置
        
        Args:
            x: X坐标（画面坐标系）
            y: Y坐标（画面坐标系）
        """
        center_x = self.frame_width // 2
        center_y = self.frame_height // 2
        
        self.offset_x = x - center_x
        self.offset_y = y - center_y
        
        self.logger.debug(f"瞄准线位置设置为: ({x}, {y}), 偏移: ({self.offset_x}, {self.offset_y})")
    
    def set_offset(self, offset_x: int, offset_y: int):
        """
        设置瞄准线偏移
        
        Args:
            offset_x: X轴偏移
            offset_y: Y轴偏移
        """
        self.offset_x = offset_x
        self.offset_y = offset_y
        
        self.logger.debug(f"瞄准线偏移设置为: ({offset_x}, {offset_y})")
    
    def get_center_position(self) -> Tuple[int, int]:
        """
        获取瞄准线中心位置
        
        Returns:
            Tuple[int, int]: (x, y) 坐标
        """
        center_x = self.frame_width // 2 + self.offset_x
        center_y = self.frame_height // 2 + self.offset_y
        return center_x, center_y
    
    def draw(self, frame: np.ndarray) -> np.ndarray:
        """
        在图像上绘制瞄准线
        
        Args:
            frame: 输入图像帧
            
        Returns:
            np.ndarray: 绘制了瞄准线的图像
        """
        result_frame = frame.copy()
        center_x, center_y = self.get_center_position()
        
        # 确保瞄准线在画面范围内
        if (center_x < 0 or center_x >= self.frame_width or 
            center_y < 0 or center_y >= self.frame_height):
            return result_frame
        
        # 根据样式绘制瞄准线
        if self.style == "cross":
            self._draw_cross(result_frame, center_x, center_y)
        elif self.style == "dot":
            self._draw_dot(result_frame, center_x, center_y)
        elif self.style == "circle":
            self._draw_circle(result_frame, center_x, center_y)
        
        # 如果在校准模式，绘制校准信息
        if self.calibration_mode:
            self._draw_calibration_info(result_frame)
        
        return result_frame
    
    def _draw_cross(self, frame: np.ndarray, center_x: int, center_y: int):
        """绘制十字瞄准线"""
        # 水平线
        cv2.line(frame, 
                (center_x - self.size, center_y), 
                (center_x + self.size, center_y), 
                self.color, self.thickness)
        
        # 垂直线
        cv2.line(frame, 
                (center_x, center_y - self.size), 
                (center_x, center_y + self.size), 
                self.color, self.thickness)
        
        # 中心点
        cv2.circle(frame, (center_x, center_y), 2, self.color, -1)
    
    def _draw_dot(self, frame: np.ndarray, center_x: int, center_y: int):
        """绘制点状瞄准线"""
        cv2.circle(frame, (center_x, center_y), self.size // 2, self.color, self.thickness)
        cv2.circle(frame, (center_x, center_y), 2, self.color, -1)
    
    def _draw_circle(self, frame: np.ndarray, center_x: int, center_y: int):
        """绘制圆形瞄准线"""
        # 外圆
        cv2.circle(frame, (center_x, center_y), self.size, self.color, self.thickness)
        
        # 内圆
        cv2.circle(frame, (center_x, center_y), self.size // 3, self.color, 1)
        
        # 中心点
        cv2.circle(frame, (center_x, center_y), 2, self.color, -1)
        
        # 十字线
        cross_size = self.size // 4
        cv2.line(frame, 
                (center_x - cross_size, center_y), 
                (center_x + cross_size, center_y), 
                self.color, 1)
        cv2.line(frame, 
                (center_x, center_y - cross_size), 
                (center_x, center_y + cross_size), 
                self.color, 1)
    
    def _draw_calibration_info(self, frame: np.ndarray):
        """绘制校准信息"""
        # 绘制校准点
        for i, point in enumerate(self.calibration_points):
            cv2.circle(frame, point, 5, (255, 0, 0), -1)
            cv2.putText(frame, f"{i+1}", 
                       (point[0] + 10, point[1] - 10),
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
        
        # 绘制校准提示
        text = f"校准模式 - 点击目标位置 ({len(self.calibration_points)}/3)"
        cv2.putText(frame, text, (10, 30),
                   cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
    
    def set_style(self, style: str, **kwargs):
        """
        设置瞄准线样式
        
        Args:
            style: 样式名称 ("cross", "dot", "circle")
            **kwargs: 其他样式参数
        """
        if style in ["cross", "dot", "circle"]:
            self.style = style
            self.logger.info(f"瞄准线样式设置为: {style}")
        
        # 更新其他参数
        if 'color' in kwargs:
            self.color = kwargs['color']
        if 'thickness' in kwargs:
            self.thickness = kwargs['thickness']
        if 'size' in kwargs:
            self.size = kwargs['size']
        if 'opacity' in kwargs:
            self.opacity = kwargs['opacity']
    
    def start_calibration(self):
        """开始校准模式"""
        self.calibration_mode = True
        self.calibration_points = []
        self.logger.info("开始瞄准线校准")
    
    def add_calibration_point(self, x: int, y: int):
        """
        添加校准点
        
        Args:
            x: 点击的X坐标
            y: 点击的Y坐标
        """
        if not self.calibration_mode:
            return
        
        self.calibration_points.append((x, y))
        self.logger.info(f"添加校准点: ({x}, {y})")
        
        # 如果有足够的校准点，计算偏移
        if len(self.calibration_points) >= 3:
            self._calculate_calibration()
    
    def _calculate_calibration(self):
        """计算校准偏移"""
        if len(self.calibration_points) < 3:
            return
        
        # 计算校准点的平均位置
        avg_x = sum(p[0] for p in self.calibration_points) / len(self.calibration_points)
        avg_y = sum(p[1] for p in self.calibration_points) / len(self.calibration_points)
        
        # 计算相对于画面中心的偏移
        center_x = self.frame_width // 2
        center_y = self.frame_height // 2
        
        self.offset_x = int(avg_x - center_x)
        self.offset_y = int(avg_y - center_y)
        
        self.logger.info(f"校准完成，偏移量: ({self.offset_x}, {self.offset_y})")
    
    def finish_calibration(self):
        """完成校准"""
        if self.calibration_mode and len(self.calibration_points) >= 3:
            self._calculate_calibration()
        
        self.calibration_mode = False
        self.logger.info("瞄准线校准完成")
    
    def cancel_calibration(self):
        """取消校准"""
        self.calibration_mode = False
        self.calibration_points = []
        self.logger.info("瞄准线校准已取消")
    
    def save_calibration(self, filepath: str):
        """
        保存校准数据
        
        Args:
            filepath: 保存文件路径
        """
        calibration_data = {
            'offset_x': self.offset_x,
            'offset_y': self.offset_y,
            'style': self.style,
            'color': self.color,
            'thickness': self.thickness,
            'size': self.size,
            'frame_width': self.frame_width,
            'frame_height': self.frame_height,
        }
        
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(calibration_data, f, indent=2, ensure_ascii=False)
            self.logger.info(f"校准数据已保存到: {filepath}")
        except Exception as e:
            self.logger.error(f"保存校准数据失败: {e}")
    
    def load_calibration(self, filepath: str) -> bool:
        """
        加载校准数据
        
        Args:
            filepath: 校准文件路径
            
        Returns:
            bool: 加载是否成功
        """
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                calibration_data = json.load(f)
            
            self.offset_x = calibration_data.get('offset_x', 0)
            self.offset_y = calibration_data.get('offset_y', 0)
            self.style = calibration_data.get('style', 'cross')
            self.color = tuple(calibration_data.get('color', [0, 255, 0]))
            self.thickness = calibration_data.get('thickness', 2)
            self.size = calibration_data.get('size', 20)
            
            self.logger.info(f"校准数据已从 {filepath} 加载")
            return True
            
        except Exception as e:
            self.logger.error(f"加载校准数据失败: {e}")
            return False
    
    def reset(self):
        """重置瞄准线到默认状态"""
        self.offset_x = 0
        self.offset_y = 0
        self.style = "cross"
        self.color = (0, 255, 0)
        self.thickness = 2
        self.size = 20
        self.calibration_mode = False
        self.calibration_points = []
        
        self.logger.info("瞄准线已重置到默认状态")